﻿using LxBasic;
using LxLESS;

namespace LxCore
{
    public class IterateSolver
    {
        public class Set<ItemType> : IInitialize, IIsEmpty where ItemType : Unit
        {
            public ItemType[] Solvers;
            public IterationTypes SolverType { get; set; } = IterationTypes.AMGV;
            public bool IsEmpty => Solvers == null || Solvers.Length == 0;
            public virtual void ClearSolver()
            {
                Solvers = null;
            }
            public virtual void CheckCreate()
            {
            }
            public void SaveOldValue()
            {
                if (IsEmpty) return;
                foreach (var s in Solvers)
                {
                    s.SaveOldValue();
                }
            }
            public void Solve_ExplicitTrans()
            {
                if (IsEmpty) return;
                foreach (var s in Solvers)
                {
                    s.Solve_ExplicitTrans();
                }
            }
            public void Solve_ImplicitTrans()
            {
                if (IsEmpty) return;
                foreach (var s in Solvers)
                {
                    s.Solve_ImplicitTrans();
                }
            }
            public void Solve_Steady()
            {
                if (IsEmpty) return;
                foreach (var s in Solvers)
                {
                    s.Solve_Steady();
                }
            }
            public void Initialize()
            {
                if (IsEmpty) return;
                foreach (var s in Solvers)
                {
                    s.Initialize();
                }
            }
        }
        public class Unit : IInitialize
        {
            protected void ParallelRun<T>(IEnumerable<T> elements, Func<T, Action<ThreadInfo>> getAct)
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var e in elements)
                    {
                        getAct.Invoke(e).Invoke(threadInfo);
                    }
                });
            }
            protected void SolveExplicit<T1, T2>(IEnumerable<T1> scalars, IEnumerable<T2> connects) where T1 : IZoneExplicitIteration where T2 : IJointIteration
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var c in connects) { c.Iterate_Copy_xArray(threadInfo); }
                    foreach (var s in scalars) { s.ExplicitIterate_Step1(threadInfo); }
                });
                MultiThreads.RunParallelTask((threadInfo) => { foreach (var s in scalars) { s.ExplicitIterate_Step2(threadInfo); } });
            }
            protected void RelaxSolveLimit<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects, IterationTypes iteType = IterationTypes.AMGV, int preSmoothSteps = 7, int postSmoothStep = 1) where T1 : MatrixBase where T2 : IJointIteration
            {
                MultiThreads.RunParallelTask((threadInfo) => { foreach (var e in matrixs) { e.ImplicitUnderRelax(threadInfo); } });
                Solve(matrixs, connects, iteType, preSmoothSteps, postSmoothStep);
                foreach (var m in matrixs) m.LimitScalarValue();
            }
            protected void Solve<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects, IterationTypes iteType = IterationTypes.AMGV, int preSmoothSteps = 7, int postSmoothStep = 1) where T1 : MatrixBase where T2 : IJointIteration
            {
                LESSSolver.Solve(matrixs, connects, iteType, preSmoothSteps, postSmoothStep);
            }
            protected void Relax<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : IJointIteration
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var e in matrixs) { e.ImplicitUnderRelax(threadInfo); }
                });
            }
            protected void CalResidual<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : IJointIteration
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var c in connects) { c.Iterate_Copy_xArray(threadInfo); }
                });
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var s in matrixs) { s.CalResidual(threadInfo); }
                });
            }
            protected void UpdateBoundsValue<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : EquationConnectBase
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var s in matrixs) { s.UpdateBoundsValue(threadInfo); }
                    foreach (var c in connects) { c.UpdateJointValue(threadInfo); }
                });
            }
            protected void Limit<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : IJointIteration
            {
                foreach (var m in matrixs) m.LimitScalarValue();
            }
            protected void FormMatrix_SteadyPart<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : EquationConnectBase
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var s in matrixs) { s.FormABOnFaces(threadInfo); }
                    foreach (var c in connects) { c.FormAbOnFaces(threadInfo); }
                });
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var e in matrixs) { e.FormABOnCells(threadInfo); }
                });
            }
            protected void FormMatrix_ExplicitTrans<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : EquationWithTransTerm
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var s in matrixs) { s.TransData.FormAb_ExplicitTrans(threadInfo); }
                });
            }
            protected void FormMatrix_ImplicitTrans<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : EquationWithTransTerm
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var s in matrixs) { s.TransData.FormAb_ImplicitTrans(threadInfo); }
                });
            }
            protected void CalGradient<T1, T2>(IEnumerable<T1> matrixs, IEnumerable<T2> connects) where T1 : MatrixBase where T2 : IJointIteration
            {
                MultiThreads.RunParallelTask((threadInfo) =>
                {
                    foreach (var e in matrixs) { e.CalGradient_LSQ(threadInfo); }
                });
            }
            protected void Initialize<T1>(IEnumerable<T1> matrixs) where T1 : IInitializable
            {
                foreach (var e in matrixs) { e.Initialize(); }
            }
            public virtual void SaveOldValue()
            {
                throw new NotImplementedException();
            }
            public virtual void Solve_ExplicitTrans()
            {
                throw new NotImplementedException();
            }
            public virtual void Solve_ImplicitTrans()
            {
                throw new NotImplementedException();
            }
            public virtual void Solve_Steady()
            {
                throw new NotImplementedException();
            }
            public virtual void Initialize()
            {
                throw new NotImplementedException();
            }
        }
    }

}

